<?php
/**
 * Created by PhpStorm.
 * User: DELL-PC
 * Date: 2018/8/2
 * Time: 9:44
 */

namespace J\Schema;


use J\Exception;
use J\Message;

/**
 * 操作元
 */
class Sprite
{
    /**
     * @var IElement
     */
    protected $element;
    /**
     * @var int PDO值类型
     */
    protected $binding;
    /**
     * @var string 操作符
     */
    protected $operator;
    /**
     * @var mixed 值
     */
    protected $value;
    /**
     * @var string 元素名称
     */
    protected $name;
    /**
     * @var string 域名城
     */
    protected $field;
    /**
     * @var string 列名称
     */
    protected $column;
    /**
     * @var mixed 默认值
     */
    protected $default;

    /**
     * @var bool 是否适用原始值
     */
    protected $raw = false;

    /**
     * Sprite constructor.
     *
     * @param IElement|string $element
     * @param mixed $value
     * @param string $operator
     * @param string $default
     * @param bool $raw
     */
    public function __construct(
        $element, $value = null, $operator = '=',
        $default = null, $raw = false
    ){
        if ($operator === null) $operator = '=';

        if ($element instanceof IElement) {
            $this->element = $element;
            $name = $element->getName();
            $this->name = $name;
            $this->field   = $element->getFieldName();
            $this->column  = $element->getColumnName();
            $this->binding = $element->getOperatorHelper()->bind();
        } else {
            $this->name = $element;
        }

        if ($value instanceof static) {
            $this->operator= $value->getOperator();
            $this->value   = $value->getValue();
            $this->default = $value->getDefault();
            $this->raw     = $value->raw;
        } else {
            $this->operator= $operator;
            $this->value   = $value;
            $this->default = $default;
            $this->raw     = $raw;
        }
    }

    /**
     * 获取表单元素值(不验证)
     * @param null|string $field
     * @param mixed $default 默认值
     * @return string
     */
    protected function getElementValue($field, $default = null)
    {
        return array_isset($_REQUEST, $field, $default);
    }

    /**
     * @return int
     */
    public function getBinding()
    {
        if (null === $this->value) return \PDO::PARAM_NULL;
        return $this->binding;
    }

    /**
     * @return string
     */
    public function getOperator()
    {
        return $this->operator;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return string
     */
    public function getField()
    {
        return $this->field;
    }

    /**
     * @return string
     */
    public function getColumn()
    {
        return $this->column;
    }

    /**
     * @return mixed
     */
    public function getDefault()
    {
        return $this->default;
    }

    protected function __clone()
    {
    }

    /**
     * 生成计算表达式
     *
     * @return Sprite
     * @throws Exception
     */
    public function mapCalculator()
    {
        if (!$this->element) return $this;

        $helper = $this->element->getOperatorHelper();

        // 检查运算符
        if ('=' !== $this->operator and !$helper->isCalculator($this->getOperator())) {
            throw new Exception(
                Message::INVALID_ELEMENT_OP,
                ['element' => $this->name, 'op' => $this->operator]
            );
        }

        // 一元运算符
        if ($helper->isEmptyCalculator($this->operator)) {
            $this->value = null;
            return $this;
        }

        // 设置为NULL
        if ($this->operator === Syntax::OPERATOR_SET_NULL and $this->element->canNull()) {
            $this->value = null;
            $this->operator = Syntax::OPERATOR_SET_NULL;
            return $this;
        }

        // 获取值
        if ($this->value === null) {
            $this->value = $this->element->getInputValue($this->default);
        }

        // 无意义的输入
        if (
            ($this->value === null)
            and ($this->element->canNull() or $this->element->hasDefault()  or !$this->element->must())
        ) {
            return null;
        }

        //TODO 这里验证Belongs有效性

        if(!$this->validValueTypeByOperator()){
            throw new Exception(
                Message::INVALID_ELEMENT_OP_PARAM,
                ['element' => $this->name, 'op' => $this->operator]
            );
        }

        // 重复数据检测
        if ($this->operator === '=' and !$this->element->unique($this->value)){
            throw new Exception(
                Message::INVALID_NOT_UNIQUE,
                ['name' => $this->getName()]
            );
        }

        // 数据有效性校验
        if ($this->operator === '=' and !$this->element->valid($this->value)){
            throw new Exception(
                Message::INVALID_ELEMENT_VALUE,
                ['element' => $this->getName(), 'collection' => $this->element->getCollection()->getName()]
            );
        }

        $this->element = null;

        return $this;
    }

    /**
     * 生成条件表达式
     *
     * @return Sprite
     * @throws Exception
     */
    public function mapCompare()
    {
        if (!$this->element) return $this;

        //  这里要注意！！！！！！！
        if ('=' === $this->operator and is_array($this->value))
            $this->operator = Syntax::OPERATOR_IN;


        $helper = $this->element->getOperatorHelper();

        if (!$helper->isCompare($this->operator)) {
            throw new Exception(
                Message::INVALID_ELEMENT_OP,
                ['element' => $this->name, 'op' => $this->operator]
            );
        }

        if ($helper->isEmptyCompare($this->operator)) {
            $this->value = null;
            return $this;
        }

        if ($this->value === null) {
            $this->value = $this->element->getInputValue($this->default);

            //  这里要注意！！！！！！！
            if ('=' === $this->operator and is_array($this->value))
                $this->operator = Syntax::OPERATOR_IN;
        }

        if(!$this->validValueTypeByOperator(false)){
            throw new Exception(
                Message::INVALID_ELEMENT_OP_PARAM,
                ['element' => $this->name, 'op' => $this->operator, 'value' => $this->value]
            );
        }

        $this->element = null;

        return $this;
    }

    /**
     * 类型校验
     *
     * @param bool $isCalculate
     * @return bool
     */
    protected function validValueTypeByOperator($isCalculate = true)
    {
        $helper = $this->element->getOperatorHelper();

        if (!is_array($this->value))
            return $helper->adaptValue($this->value, $this->operator);

        if (!$this->isArrayOperator($isCalculate))
            return false;

        foreach ($this->value as &$v) {
            if(!$helper->adaptValue($v, $this->operator)) return false;
        }
        return true;
    }

    protected function isEmptyOperator($isCalculate)
    {
        $helper = $this->element->getOperatorHelper();
        return (
        ($isCalculate) ?
            $helper->isEmptyCalculator($this->operator) :
            $helper->isEmptyCompare($this->operator)
        );
    }

    protected function isArrayOperator($isCalculate)
    {
        $helper = $this->element->getOperatorHelper();
        return ($isCalculate?
            $helper->isArrayCalculator($this->operator) :
            $helper->isArrayCompare($this->operator)
        );
    }
}